package com.shareyi.baseproject.kernel.common.event;

import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.SubscriberExceptionContext;
import com.shareyi.baseproject.kernel.common.retry.RetrySubscriber;
import com.shareyi.baseproject.kernel.common.utils.LogHelper;

import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * 基于Guava的{@linkplain EventBus}事件管理器
 *
 * @author qiulong
 */
class EventBusManager implements EventManager {

    /**
     * 事件管理器
     */
    private ConcurrentHashMap<String, EventBus> manager = new ConcurrentHashMap<String, EventBus>();

    @Override
    public void pub(String topic, Event event) {
        checkNotNull(topic);
        checkNotNull(event);
        EventBus eventBus = manager.get(topic);
        if (eventBus == null) {
            eventBus = createEventBus(topic, null);
            EventBus old = manager.putIfAbsent(topic, eventBus);
            if (old != null) {
                eventBus = old;
            }
        }
        eventBus.post(event);
    }

    @Override
    public void sub(String topic, SubscribeAware subscriber) {
        this.sub(topic, subscriber, null);
    }

    @Override
    public void sub(final String topic, SubscribeAware subscriber, final EventExceptionHandler exceptionHandler) {
        checkNotNull(topic);
        checkNotNull(subscriber);
        EventBus eventBus = manager.get(topic);
        if (eventBus == null) {
            eventBus = createEventBus(topic, exceptionHandler);
            EventBus old = manager.putIfAbsent(topic, eventBus);
            if (old != null) {
                eventBus = old;
            }
        }
        eventBus.register(subscriber);
    }

    @Override
    public void unsub(String topic, SubscribeAware subscriber) {
        checkNotNull(topic);
        checkNotNull(subscriber);
        EventBus eventBus = manager.get(topic);
        if (eventBus != null) {
            eventBus.unregister(subscriber);
        }
    }

    /**
     * 创建事件总线
     *
     * @param topic
     * @param exceptionHandler
     * @return
     */
    private EventBus createEventBus(String topic, final EventExceptionHandler exceptionHandler) {
        EventBus eventBus;
        if (exceptionHandler == null) {
            eventBus = new EventBus(topic);
        } else {
            eventBus = new EventBus((exception, context) -> {
                Object event = context.getEvent();
                //  context.get
                if (event instanceof Event) {
                    String subscriberName = getSubscriberName(context);
                    exceptionHandler.handleException(exception, (Event) event, subscriberName);
                } else {
                    LogHelper.EXCEPTION.warn("[事件总线]创建事件总线传递类型异常，非Event，event：{}", event);
                }
            });
        }
        return eventBus;
    }

    /**
     * 获取订阅者名称,在订阅方法上注解获取
     * 从 RetrySubscriber 注解获取，如果没有，返回空
     *
     * @param context
     * @return
     */
    private String getSubscriberName(SubscriberExceptionContext context) {
        Method subscriberMethod = context.getSubscriberMethod();
        RetrySubscriber retrySubscriber = subscriberMethod.getAnnotation(RetrySubscriber.class);
        return retrySubscriber == null ? null : retrySubscriber.value();
    }

}
